package com.iwomy.secureplat.platform.transmission.parse;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.googlecode.aviator.AviatorEvaluator;
import com.iwomy.secureplat.common.data.tenant.TenantBroker;
import com.iwomy.secureplat.platform.constant.RedisConstants;
import com.iwomy.secureplat.platform.constant.RedisExpirationTime;
import com.iwomy.secureplat.platform.entity.*;
import com.iwomy.secureplat.platform.service.AlarmBaseService;
import com.iwomy.secureplat.platform.transmission.DrcProInfo;
import com.iwomy.secureplat.platform.transmission.constant.ProtocolConstant;
import com.iwomy.secureplat.platform.transmission.entity.SensorTransmissionData;
import com.iwomy.secureplat.platform.transmission.entity.SensorTransmissionDataDetails;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.sql.Connection;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.iwomy.secureplat.platform.transmission.constant.ProtocolConstant.DATA_LENGTH;
import static com.iwomy.secureplat.platform.transmission.constant.ProtocolConstant.DATA_LENGTH_INDEX;

/**
 * 解析安帕尔私有协议数据
 *
 * @author yangze
 * 2019-08-21
 */
@Slf4j
@Data
public class EmpaerDataParse implements ParseData, AlarmBaseService {


	public DrcProInfo drcProInfo;
	//原数据
//	private byte[] srcData;
	//帧头
//	private byte frameHeader;
	//从帧类型开始，到数据段结束的所有字节数，2个字节。
//	private byte[] dataLength = new byte[2];
	//帧类型：接收帧默认“0X90”，1 字节。
//	private byte frameType;
	//MAC 长地址：64BITS,8 字节，可以在设备上查看。
//	private byte[] macAddress = new byte[8];
	//16 位短地址：ZIGBEE 组网后自动生成的 16 位网络地址，2字节，一般默认“FF FE”。
//	private byte[] shortAddress = new byte[2];
	//自动应答选项：接收帧默认“0X01”，1 字节。
//	private byte autoAnswer;
	//数据段自身有自己的独立的帧结构，按照功能使用不同的命令字。需要说明的是这个数据段的长度有约束，在 64 字节以内。
//	private byte[] dataSegment;
	//除了“帧头”、“长度”和“校验和”之外，所有数据的 8 位不带进位累加，得到的总和，在 0XFF 里面减去这个数，就得到“校验和”，1 字节。
//	private byte checksum;

//	private SensorTransmissionData sensorTransmissionData;


//	private BasicInstallLocationEntity installLocation;

//	private BasicAlarmContactsEntity alarmContacts;


//	private DeviceInfo deviceInfo = new DeviceInfo();
//	private Map<String, ParamInfo> name2ParamInfoMap= new HashMap<String, ParamInfo>();

	private static Connection conn = null;
	private Date lastDataTime = new Date();
	private boolean isHeartPk = false;

	public EmpaerDataParse() {

	}


	@Override
	public boolean decoder(ByteBuf in, List<Object> list) {
//		7E 00 2E 90 00 08 00 00 10 24 19 01 FF FE 01 AA 1F 87 01 08 13 00 00 23 12 22 12 08 48 03 01 20 66 66 A6 41 FF 6F 00 00 00 00 FE 7F 00 00 00 00 3D F7


		int totalLength = in.readableBytes();
		if (totalLength < 9) return false;
		log.info("报文总长度:{}", totalLength);

		byte[] srcData = new byte[in.readableBytes()];
		in.readBytes(srcData);

		if (ObjectUtil.isEmpty(srcData)) return false;
		//拆分数据,先标准解析，后面处理粘包等问题

		list.add(srcData);

		return true;
	}

	@Override
	//01 03 04 A1 20 00 07 99 C7
	//报文解释说明：“01”设备地址；“03”读功能码；“04”数据长度；“A1 20 00 07”为寄存器值；“99 C7”校验码。计算负氧离子： 0x0007A120=500000个
	public SensorTransmissionData parse(byte[] data, BasicDeviceEntity device) {

		log.info("设备报文:{}", HexUtil.encodeHexStr(data));

		//处理粘包
		for (int i = 0; i < data.length; i++) {
			byte datum = data[i];
			if (datum != 0x7E) continue;
			if (i == 0) break;
			byte[] temp = new byte[data.length - i];
			System.arraycopy(data, i, temp, 0, data.length - i);
			data = temp;
			break;
		}


		byte frameHeader = data[ProtocolConstant.FRAME_HEADER_INDEX];
		if (frameHeader != 0x7E) {
			log.error("报文不合法,帧头:{}", HexUtil.toHex(frameHeader));
			return null;
		}
		//从帧类型开始，到数据段结束的所有字节数
		byte[] dataLength = new byte[2];
		System.arraycopy(data, DATA_LENGTH_INDEX, dataLength, 0, DATA_LENGTH);
		int length = ((dataLength[dataLength[0]]) << 8) | (byte2Hex(dataLength[1]));
//		log.info("长度：{}    {}", length, HexUtil.toHex(length));
		//帧类型到数据段的长度
		int frameType2DataSegment = length - 12;
//		log.info("帧类型到数据段的长度：{}    {}", dataLength, HexUtil.toHex(frameType2DataSegment));
		byte[] macAddress = new byte[8];
		System.arraycopy(data, 4, macAddress, 0, 8);
		String macStr = HexUtil.encodeHexStr(macAddress);
		log.info("安帕尔私有协议设备MAC:{}", macStr);
		BasicDeviceEntity byImei = basicDeviceService.getByImei(macStr);
		if (ObjectUtil.isEmpty(byImei)) {
			log.error("设备未添加:{}", macStr);
			return null;
		}
		BeanUtil.copyProperties(byImei, device);
//		device = basicDeviceService.getByImei(macStr);
		byte[] dataSegment = new byte[length - 12];
		System.arraycopy(data, 15, dataSegment, 0, length - 12);
		log.info("数据内容:{}", HexUtil.encodeHexStr(dataSegment));
//		byte checksum = data[data.length - 1];

		SensorTransmissionData transmissionData = this.parseDataSegments(device, dataSegment);


		if (ObjectUtil.isEmpty(transmissionData.getSensorTransmissionDataDetailsList())) return null;
		DeviceLogEntity deviceLogEntity = new DeviceLogEntity();
		deviceLogEntity.setDeviceUniqueId(transmissionData.getDeviceUniqueId());
		deviceLogEntity.setContent(HexUtil.encodeHexStr(data));
		deviceLogService.save(deviceLogEntity);
		return transmissionData;
	}

	@Override
	public boolean isHeartPack() {

		return this.isHeartPk;
	}

	@Override
	public Date getLastHeartPackDate() {
		return this.lastDataTime;
	}


	@Override
	public boolean alarm(BasicDeviceEntity device, SensorTransmissionData transmissionData) {
		//先判断是否故障,再判断是否设备报警，最后规则报警
		boolean b = this.alarmJudgment(device, transmissionData);
		this.save(b, device, transmissionData);
		return true;
	}


	@Override
	public boolean save(Boolean updateDeviceState, BasicDeviceEntity basicDeviceEntity, SensorTransmissionData transmissionData) {
		//保存数据,如果一定时间内没数据过来，出发联网超时报警（2分钟），用redis做
		String key = RedisConstants.REDIS_KEY_DEVICE_ONLINE + basicDeviceEntity.getImei();
		if (!redisClient.expire(key, 5 * 60 * 1000) || updateDeviceState) {
			redisClient.set(key, JSONObject.toJSONString(basicDeviceEntity), 5 * 60 * 1000);
			basicDeviceEntity.setOnline(20);
			basicDeviceService.updateById(basicDeviceEntity);
			log.info("{}:接收到设备报文,更新设备状态为在线",basicDeviceEntity.getImei());
		}
		String dataKey = RedisConstants.REDIS_KEY_DEVICE_REALTIME_DATA + basicDeviceEntity.getImei();
		redisClient.set(dataKey, JSONObject.toJSONString(transmissionData), RedisExpirationTime.REDIS_TIME_DEVICE_REALTIME_DATA);

		String intervalKey = RedisConstants.REDIS_KEY_DEVICE_EVEN_INTERVAL + basicDeviceEntity.getImei();
		// 心跳数据10分钟存一次
		long interval = redisClient.getTime(intervalKey);
		//剩余时间小于2分钟或类型不是心跳则更新数据
		if(interval>RedisExpirationTime.REDIS_TIME_DEVICE_REALTIME_INTERVAL&&"HEARTBEAT".equals(transmissionData.getAlarmEvenCode()))
		{
			return false;
		}
		redisClient.set(intervalKey, "", RedisExpirationTime.REDIS_TIME_DEVICE_REALTIME_DATA);
		mongoTemplate.save(transmissionData);
		return true;
	}

	@Override
	public void setDrcProInfo(DrcProInfo drcProInfo) {
		this.drcProInfo = drcProInfo;
	}

	@Override
	public DrcProInfo getDrcProInfo() {
		return this.drcProInfo;
	}

	/**
	 * 解析数据段内容
	 *
	 * @param dataSegment
	 */
	private SensorTransmissionData parseDataSegments(BasicDeviceEntity basicDeviceEntity, byte[] dataSegment) {

		//读取的索引
		Integer readIndex = 0;
		byte dateFrameHeader = dataSegment[0];
		if (byte2Hex(dateFrameHeader) != 0xAA) {
			log.error("数据段帧头错误:{}", HexUtil.toHex(byte2Hex(dateFrameHeader)));
		}


		byte deviceProperties = dataSegment[4];
		log.info("设备属性:{}", HexUtil.toHex(byte2Hex(deviceProperties)));
		byte protocolVersion = dataSegment[5];
		log.info("协议版本:{}", HexUtil.toHex(byte2Hex(protocolVersion)));
		byte[] alarmInfo = new byte[2];
		System.arraycopy(dataSegment, 6, alarmInfo, 0, alarmInfo.length);
		ArrayUtil.swap(alarmInfo, 0, 1);

//		readIndex = copyAndMoveReadIndexOrder(dataSegment, 6, alarmInfo);
		// 该项置位为发生报警，置零为该项未报警。多种报警信息并存支持，2 字节。部分功能为预留功能。
		// 常见的有：00 00 正常；01 00 低报警；02 00 高报警；04 00 超量程
		SensorTransmissionData sensorTransmissionData = new SensorTransmissionData();
		List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = new ArrayList<>();


//		sensorTransmissionData.setAlarmInfo("0x" + HexUtil.encodeHexStr(alarmInfo));
		int value = ((alarmInfo[0] & 0xFF) << 8) | (alarmInfo[1] & 0xFF);
		sensorTransmissionData.setAlarmInfo(String.format("0x%04X", value));
		log.info("报警信息:{}", sensorTransmissionData.getAlarmInfo());
		byte[] timeStamp = new byte[6];
		System.arraycopy(dataSegment, 8, timeStamp, 0, timeStamp.length);
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
		LocalDateTime receptionTime = LocalDateTime.parse(HexUtil.encodeHexStr(timeStamp), formatter);
//		sensorTransmissionData.setReceptionTime(receptionTime);
		sensorTransmissionData.setReceptionTime(LocalDateTime.now());
		log.info("时间戳:{},{}", HexUtil.encodeHexStr(timeStamp), receptionTime);
		byte numberData = dataSegment[14];
		log.info("数据个数:{}", HexUtil.toHex(byte2Hex(numberData)));
		readIndex = 15;
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < numberData; i++) {
//            log.info("测试+={}", readIndex += 1);

			byte[] gasTypeIdAndUnit = new byte[2];
			readIndex = copyAndMoveReadIndexOrder(dataSegment, readIndex, gasTypeIdAndUnit);
			log.debug("气体类型和单位:0x{}", HexUtil.encodeHexStr(gasTypeIdAndUnit));
//            byte unit = dataSegment[readIndex += 1];
//            //用户添加传感器信息的时候 0x单位传感器信息  注意先后顺序
//            log.info("单位:{}", HexUtil.toHex(byte2Hex(unit)));
//            byte gasTypeId = dataSegment[readIndex += 1];
//            log.info("气体类型id:{}", HexUtil.toHex(byte2Hex(gasTypeId)));
			byte[] val = new byte[4];
			readIndex = copyAndMoveReadIndex(dataSegment, readIndex, val);
			String vatStr = HexUtil.encodeHexStr(val);
			float gasValFloat = ByteBuffer.wrap(val).order(ByteOrder.LITTLE_ENDIAN).getFloat();
			DecimalFormat df = new DecimalFormat("#.###");
			String gasVal = df.format(gasValFloat);
			gasTypeIdAndUnit = ArrayUtil.swap(gasTypeIdAndUnit, 0, 1);
			value = ((gasTypeIdAndUnit[0] & 0xFF) << 8) | (gasTypeIdAndUnit[1] & 0xFF);
			int typeId = value & 0xFFF;
			int unitId = (value >> 12) & 0xF;
			String gasType = String.format("0x%04X", typeId);

			String gasUnit = String.format("0x%02X", unitId);
			BasicSensorUnitEntity basicSensorUnitEntity = basicSensorUnitService.oneByUnitCode(gasUnit);


//			String gasType = "0x" + HexUtil.toHex(byte2Hex(gasTypeIdAndUnit[0]));
//			String gasUnit = "0x" + HexUtil.toHex(byte2Hex(gasTypeIdAndUnit[1]));
			LambdaQueryWrapper<BasicSensorEntity> queryWrapper = Wrappers.lambdaQuery(new BasicSensorEntity())
					.eq(BasicSensorEntity::getSensorTypeCode, gasType);
//					.eq(BasicSensorEntity::getDeviceModelId, basicDeviceEntity.getDeviceModelId())
//					.eq(BasicSensorEntity::getDeviceTypeId, basicDeviceEntity.getDeviceTypeId())
//					.eq(BasicSensorEntity::getTenantId, basicDeviceEntity.getTenantId());
			BasicSensorEntity basicSensorEntity = basicSensorService.getOne(queryWrapper);
			String s = ObjectUtil.isNull(basicSensorEntity) ? gasType : basicSensorEntity.getSensorTypeName();
			String znName = ObjectUtil.isNull(basicSensorEntity) ? null : basicSensorEntity.getZhName();
			String detectionTypeName = ObjectUtil.isNull(basicSensorEntity) ? null : basicSensorEntity.getDetectionTypeName();
			log.info("气体类型:{},{}", s, gasType);
			log.info("单位:{},{}", basicSensorUnitEntity.getSensorUnitName(), gasUnit);
			log.info("值:0x{},{}", vatStr, gasVal);
			log.info("中文名称:{}", znName);
			log.info("检测类型名:{}", detectionTypeName);
			SensorTransmissionDataDetails sensorDetails =
					new SensorTransmissionDataDetails(gasType
							, s
							, basicSensorUnitEntity.getSensorUnitCode(), basicSensorUnitEntity.getSensorUnitName(), s + basicSensorUnitEntity.getSensorUnitName(), gasVal, znName, detectionTypeName);
			sensorTransmissionDataDetailsList.add(sensorDetails);

			sb.append(sensorDetails.getZhName())
					.append("(").append(sensorDetails.getDetectionTypeName()).append("):")
					.append(sensorDetails.getSensorVal()).append(";");
			sensorTransmissionData.setContent(sb.toString());
		}
		sensorTransmissionData.setSensorTransmissionDataDetailsList(sensorTransmissionDataDetailsList);
		sensorTransmissionData.setDeviceUniqueId(basicDeviceEntity.getImei());
		sensorTransmissionData.setAlarmEvenCode("HEARTBEAT");
		sensorTransmissionData.setAlarmEvenName("心跳");

		sensorTransmissionData.setAlarmTypeCode("HEARTBEAT");
		sensorTransmissionData.setAlarmTypeName("心跳");
		sensorTransmissionData.setTenantId(basicDeviceEntity.getTenantId());
		sensorTransmissionData.setDeptId(basicDeviceEntity.getDeptId());
		return sensorTransmissionData;
	}


	@Override
	public boolean faultAlarm(BasicDeviceEntity basicDeviceEntity, SensorTransmissionData transmissionData) {
		List<AlarmEventTypeEntity> faultAlarm = alarmEventTypeService
				.listByBasicDeviceAndCode(basicDeviceEntity, "FAULT_ALARM",
						transmissionData.getAlarmInfo(), "empaer");
		if (ObjectUtil.isEmpty(faultAlarm)) {
			log.error("{}，没有找到对应的故障报警事件", basicDeviceEntity.getImei());
			return false;
		}
		//新增一条故障记录
		BasicInstallLocationEntity installLocation = basicInstallLocationService.getById(basicDeviceEntity.getInstallLocationId());
		if (ObjectUtil.isEmpty(installLocation)) return false;
		BasicAlarmContactsEntity alarmContacts = basicAlarmContactsService.getById(installLocation.getAlarmWorkerId());
		if (ObjectUtil.isEmpty(alarmContacts)) return false;
		List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = transmissionData.getSensorTransmissionDataDetailsList();
		StringBuffer sb = new StringBuffer();
		sensorTransmissionDataDetailsList.stream().forEach(x -> {
			sb.append(x.getZhName()).append("(").append(x.getDetectionTypeName()).append(")当前值").append(x.getSensorVal())
					.append(",");
		});
		if(sb.length()>1)
			sb.deleteCharAt(sb.length() - 1);
		for (AlarmEventTypeEntity x : faultAlarm) {
			{
				if (!redisClient.tryLock("alarm:faultAlarm:" + basicDeviceEntity.getId() + ":" + x.getAlarmTypeCode(), ""
						, 5 * 60)) {
					log.error("设备故障,{}:{}分钟内重复", JSONObject.toJSONString(x), 5);
					continue;
				}
				AlarmFaultLoggingEntity faultLogging = new AlarmFaultLoggingEntity();
				faultLogging.setDeptId(basicDeviceEntity.getDeptId());
				faultLogging.setTenantId(basicDeviceEntity.getTenantId());
				alarmFaultLoggingService.save(faultLogging);
//				faultLogging.setAlarmCauses(x.getAlarmTypeName());
				faultLogging.setAlarmCauses(sb.toString());
				faultLogging.setDeviceId(basicDeviceEntity.getId());
				faultLogging.setImei(basicDeviceEntity.getImei());
				faultLogging.setEventTypeId(x.getId());
				faultLogging.setEventTypeName(x.getEventTypeName());
				faultLogging.setDeviceTypeId(basicDeviceEntity.getDeviceTypeId());
				faultLogging.setDeviceTypeName(basicDeviceEntity.getDeviceTypeName());
				faultLogging.setDeviceModelId(basicDeviceEntity.getDeviceModelId());
				faultLogging.setDeviceModelName(basicDeviceEntity.getDeviceModelName());
				faultLogging.setInstallLocationId(basicDeviceEntity.getInstallLocationId());

				BasicNotificationRecordEntity sendSmsMsgNotificationRecord =
						this.sendSmsMsg(basicDeviceEntity, installLocation, alarmContacts, faultLogging.getAlarmCauses());
				basicNotificationRecordService.save(sendSmsMsgNotificationRecord);
				faultLogging.setSmsAlarmId(sendSmsMsgNotificationRecord.getId());
				faultLogging
						.setSmsAlarmSketch(sendSmsMsgNotificationRecord.getSketch());
				BasicNotificationRecordEntity callPhoneNotificationRecord =
						this.callPhone(basicDeviceEntity, installLocation, alarmContacts, faultLogging.getAlarmCauses());
				basicNotificationRecordService.save(callPhoneNotificationRecord);
				faultLogging.setTelephoneAlarmId(callPhoneNotificationRecord.getId());
				faultLogging
						.setTelephoneAlarmSketch(callPhoneNotificationRecord.getSketch());


				BasicNotificationRecordEntity officialAccountNotificationRecord =
						this.sendOfficialAccountMsg(basicDeviceEntity, installLocation,
								alarmContacts, faultLogging.getAlarmCauses(), faultLogging);
				basicNotificationRecordService.save(officialAccountNotificationRecord);
				faultLogging.setOfficialAccountAlarmId(officialAccountNotificationRecord.getId());
				faultLogging
						.setOfficialAccountAlarmSketch(officialAccountNotificationRecord.getSketch());
				transmissionData.setAlarmEvenCode(x.getEventTypeCode());
				transmissionData.setAlarmEvenName(x.getEventTypeName());
				transmissionData.setAlarmTypeCode("FAULT_ALARM");
				transmissionData.setAlarmTypeName("故障报警");
				alarmFaultLoggingService.updateById(faultLogging);
				basicDeviceEntity.setDeviceState(30);
				basicDeviceEntity.setRecentEventTime(LocalDateTime.now());
			}
			return true;
		}

		return false;
	}

	@Override
	public boolean equipmentAlarm(BasicDeviceEntity basicDeviceEntity, SensorTransmissionData transmissionData) {
		List<AlarmEventTypeEntity> deviceAlarm = alarmEventTypeService
				.listByBasicDeviceAndCode(basicDeviceEntity, "DEVICE_ALARM",
						transmissionData.getAlarmInfo(), "empaer");
		if (ObjectUtil.isEmpty(deviceAlarm)) {
			log.error("{}，没有找到对应的设备报警事件", basicDeviceEntity.getImei());
			return false;
		}
		BasicInstallLocationEntity installLocation = basicInstallLocationService.getById(basicDeviceEntity.getInstallLocationId());
		if (ObjectUtil.isEmpty(installLocation)) return false;
		BasicAlarmContactsEntity alarmContacts = basicAlarmContactsService.getById(installLocation.getAlarmWorkerId());
		if (ObjectUtil.isEmpty(alarmContacts)) return false;
		List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = transmissionData.getSensorTransmissionDataDetailsList();
		StringBuffer sb = new StringBuffer();
		sensorTransmissionDataDetailsList.stream().forEach(x -> {
			sb.append(x.getZhName()).append("(").append(x.getDetectionTypeName()).append(")当前值").append(x.getSensorVal())
					.append(",");
		});
		if(sb.length()>1)
			sb.deleteCharAt(sb.length() - 1);


		for (AlarmEventTypeEntity x : deviceAlarm) {
			{
				//根据事件类型判断是否报警
				if (!redisClient.tryLock("alarm:equipmentAlarm:" + basicDeviceEntity.getId() + ":" + x.getEventTypeCode(), ""
						, 5 * 60)) {
					log.error("设备报警,{}:{}分钟内重复", JSONObject.toJSONString(x), 5);
					continue;
				}
				AlarmLoggingEntity alarmLoggingEntity = new AlarmLoggingEntity();
				alarmLoggingEntity.setDeptId(basicDeviceEntity.getDeptId());
				alarmLoggingEntity.setTenantId(basicDeviceEntity.getTenantId());
				alarmLoggingService.save(alarmLoggingEntity);
				alarmLoggingEntity
						.setAlarmCauses(sb.toString());
				alarmLoggingEntity.setDeviceId(basicDeviceEntity.getId());
				alarmLoggingEntity.setImei(basicDeviceEntity.getImei());
				alarmLoggingEntity.setDeviceTypeId(basicDeviceEntity.getDeviceTypeId());
				alarmLoggingEntity.setDeviceTypeName(basicDeviceEntity.getDeviceTypeName());
				alarmLoggingEntity.setDeviceModelId(basicDeviceEntity.getDeviceModelId());
				alarmLoggingEntity.setDeviceModelName(basicDeviceEntity.getDeviceModelName());
				alarmLoggingEntity.setInstallLocationId(basicDeviceEntity.getInstallLocationId());
				alarmLoggingEntity.setEventTypeId(x.getId());
				alarmLoggingEntity.setEventTypeName(x.getEventTypeName());

				alarmLoggingEntity.setInstallLocationDetailAddress(installLocation.getDetailAddress());
				alarmLoggingEntity.setLatitude(installLocation.getLatitude());
				alarmLoggingEntity.setLongitude(installLocation.getLongitude());
				alarmLoggingEntity.setName(alarmContacts.getName());
				alarmLoggingEntity.setPhone(alarmContacts.getPhone());
				alarmLoggingEntity.setAddress(installLocation.getAddress());
				BasicNotificationRecordEntity sendSmsMsgNotificationRecord =
						this.sendSmsMsg(basicDeviceEntity, installLocation, alarmContacts, alarmLoggingEntity.getAlarmCauses());
				basicNotificationRecordService.save(sendSmsMsgNotificationRecord);
				alarmLoggingEntity.setSmsAlarmId(sendSmsMsgNotificationRecord.getId());
				alarmLoggingEntity
						.setSmsAlarmSketch(sendSmsMsgNotificationRecord.getSketch());


				BasicNotificationRecordEntity callPhoneNotificationRecord =
						this.callPhone(basicDeviceEntity, installLocation, alarmContacts, alarmLoggingEntity.getAlarmCauses());
				basicNotificationRecordService.save(callPhoneNotificationRecord);
				alarmLoggingEntity.setTelephoneAlarmId(callPhoneNotificationRecord.getId());
				alarmLoggingEntity
						.setTelephoneAlarmSketch(callPhoneNotificationRecord.getSketch());


				BasicNotificationRecordEntity officialAccountNotificationRecord =
						this.sendOfficialAccountMsg(basicDeviceEntity, installLocation
								, alarmContacts, alarmLoggingEntity.getAlarmCauses(), alarmLoggingEntity);
				basicNotificationRecordService.save(officialAccountNotificationRecord);
				alarmLoggingEntity.setOfficialAccountAlarmId(officialAccountNotificationRecord.getId());
				alarmLoggingEntity
						.setOfficialAccountAlarmSketch(officialAccountNotificationRecord.getSketch());
				alarmLoggingService.updateById(alarmLoggingEntity);
				transmissionData.setAlarmEvenCode(x.getEventTypeCode());
				transmissionData.setAlarmEvenName(x.getEventTypeName());
				transmissionData.setAlarmTypeCode("DEVICE_ALARM");
				transmissionData.setAlarmTypeName("设备报警");


				log.info(alarmLoggingEntity.getAlarmCauses());
				webSocketMsg(basicDeviceEntity, alarmLoggingEntity);
				basicDeviceEntity.setDeviceState(40);
				basicDeviceEntity.setRecentEventTime(LocalDateTime.now());
				return true;
			}


		}
		//新增一条设备报警记录
		return false;
	}

	@Override
	public boolean rulesAlarm(BasicDeviceEntity basicDeviceEntity, SensorTransmissionData transmissionData) {


		//根据
		List<SensorTransmissionDataDetails> sensorTransmissionDataDetailsList = transmissionData.getSensorTransmissionDataDetailsList();
//		List<String> sensorIds = sensorTransmissionDataDetailsList.stream().map(SensorTransmissionDataDetails::getSensorType).collect(Collectors.toList());
		List<AlarmRulesEntity> alarmRulesEntities = alarmRulesService.listByDevice(basicDeviceEntity);
//		List<AlarmRulesEntity> alarmRulesEntities = alarmRulesService.listBySensorIds(basicDeviceEntity, sensorIds);
		if (ObjectUtil.isEmpty(alarmRulesEntities)) {
			log.error("{}，没有找到对应的报警规则", basicDeviceEntity.getImei());
			return false;
		}


		Map<String, SensorTransmissionDataDetails> sensorMap = sensorTransmissionDataDetailsList.stream()
				.collect(Collectors.toMap(SensorTransmissionDataDetails::getSensorType, Function.identity(), (existing, replacement) -> existing));

		BasicInstallLocationEntity installLocation = basicInstallLocationService.getById(basicDeviceEntity.getInstallLocationId());
		if (ObjectUtil.isEmpty(installLocation)) return false;
		BasicAlarmContactsEntity alarmContacts = basicAlarmContactsService.getById(installLocation.getAlarmWorkerId());
		if (ObjectUtil.isEmpty(alarmContacts)) return false;

		for (AlarmRulesEntity alarmRulesEntity :
				alarmRulesEntities) {
			String calcExpression = alarmRulesEntity.getCalcExpression();
			HashMap<String, Object> map = new HashMap<>();
			SensorTransmissionDataDetails sensorTransmissionDataDetails = sensorMap.get(alarmRulesEntity.getSensorTypeCode());
			if (ObjectUtil.isNull(sensorTransmissionDataDetails)) {
				log.debug("{}传感器数值为空", alarmRulesEntity.getSensorTypeCode());
				continue;
			}
			String sensorVal = sensorTransmissionDataDetails.getSensorVal();
			log.info("{}规则检测{},值{}", basicDeviceEntity.getImei(), alarmRulesEntity.getSensorTypeName(), sensorVal);
			map.put("para", new BigDecimal(sensorVal).doubleValue());
			//规则引擎，判断是否出发规则报警
			boolean execute = false;
			try {
				execute = (boolean) AviatorEvaluator.execute(calcExpression, map);
			} catch (Exception e) {
				log.error("规则解析错误：{}", e.getMessage());
			}

			if (!execute) continue;
			if (!redisClient.tryLock("alarm:rulesAlarm:" + basicDeviceEntity.getId() + ":" + alarmRulesEntity.getSensorTypeName() , ""
					, 5 * 60)) {
				log.error("规则报警,{}:{}分钟内重复", JSONObject.toJSONString(alarmRulesEntity), 5);
				continue;
			}
			AlarmLoggingEntity alarmLoggingEntity = new AlarmLoggingEntity();
			alarmLoggingEntity.setDeptId(basicDeviceEntity.getDeptId());
			alarmLoggingEntity.setTenantId(basicDeviceEntity.getTenantId());
			alarmLoggingService.save(alarmLoggingEntity);
			alarmLoggingEntity
					.setAlarmCauses(alarmRulesEntity.getSensorTypeName() + "当前值:" + sensorVal
							+ "满足报警条件:" + alarmRulesEntity.getExpression());
			alarmLoggingEntity.setDeviceId(basicDeviceEntity.getId());
			alarmLoggingEntity.setImei(basicDeviceEntity.getImei());
			alarmLoggingEntity.setDeviceTypeId(basicDeviceEntity.getDeviceTypeId());
			alarmLoggingEntity.setDeviceTypeName(basicDeviceEntity.getDeviceTypeName());
			alarmLoggingEntity.setDeviceModelId(basicDeviceEntity.getDeviceModelId());
			alarmLoggingEntity.setDeviceModelName(basicDeviceEntity.getDeviceModelName());
			alarmLoggingEntity.setInstallLocationId(basicDeviceEntity.getInstallLocationId());
			alarmLoggingEntity.setEventTypeId(alarmRulesEntity.getId());
			alarmLoggingEntity.setEventTypeName(alarmRulesEntity.getRuleName());

			alarmLoggingEntity.setInstallLocationDetailAddress(installLocation.getDetailAddress());
			alarmLoggingEntity.setLatitude(installLocation.getLatitude());
			alarmLoggingEntity.setLongitude(installLocation.getLongitude());
			alarmLoggingEntity.setName(alarmContacts.getName());
			alarmLoggingEntity.setPhone(alarmContacts.getPhone());
			alarmLoggingEntity.setAddress(installLocation.getAddress());

			BasicNotificationRecordEntity sendSmsMsgNotificationRecord =
					this.sendSmsMsg(basicDeviceEntity, installLocation, alarmContacts, alarmRulesEntity.getRuleName());
			basicNotificationRecordService.save(sendSmsMsgNotificationRecord);
			alarmLoggingEntity.setSmsAlarmId(sendSmsMsgNotificationRecord.getId());
			alarmLoggingEntity
					.setSmsAlarmSketch(sendSmsMsgNotificationRecord.getSketch());

			BasicNotificationRecordEntity callPhoneNotificationRecord =
					this.callPhone(basicDeviceEntity, installLocation, alarmContacts, alarmRulesEntity.getRuleName());
			basicNotificationRecordService.save(callPhoneNotificationRecord);
			alarmLoggingEntity.setTelephoneAlarmId(callPhoneNotificationRecord.getId());
			alarmLoggingEntity
					.setTelephoneAlarmSketch(callPhoneNotificationRecord.getSketch());

			BasicNotificationRecordEntity officialAccountNotificationRecord =
					this.sendOfficialAccountMsg(basicDeviceEntity, installLocation
							, alarmContacts, alarmRulesEntity.getRuleName(), alarmLoggingEntity);
			basicNotificationRecordService.save(officialAccountNotificationRecord);
			alarmLoggingEntity.setOfficialAccountAlarmId(officialAccountNotificationRecord.getId());
			alarmLoggingEntity
					.setOfficialAccountAlarmSketch(officialAccountNotificationRecord.getSketch());
			//todo 判断是否需要发送视频弹窗
			webSocketMsg(basicDeviceEntity, alarmLoggingEntity);

			alarmLoggingService.updateById(alarmLoggingEntity);
			transmissionData.setAlarmEvenCode(alarmRulesEntity.getRuleName());
			transmissionData.setAlarmEvenName(alarmRulesEntity.getRuleName());
			transmissionData.setAlarmTypeCode("RULES_ALARM");
			transmissionData.setAlarmTypeName("规则报警");
			log.info(alarmLoggingEntity.getAlarmCauses());
			basicDeviceEntity.setDeviceState(40);
			basicDeviceEntity.setRecentEventTime(LocalDateTime.now());
			return true;
		}
		//新增规则报警记录
		return false;
	}


}